bash
scripts
References are to the Bash Manual.
Line break
A command can be broken over several input line by ending lines with a backslash:
find ~ -name ".*" -prune -o -type f \
-name "*.text" -print -o \
-name "*.md" -print -o \
-name "*.qmd" -print -o \
-name "*.Rmd" -print -o \
-name "*.Rmd" -print > mdfiles.txt
Redirections
Redirect file to stdin: <cmd> < <file>
Redirect stdout to file: <cmd> > <file>
Redirect stdout to file, appending: <cmd> >> <file>
Redirect stderr to file: <cmd> 2> <file>
Redirect stderr to stdout: <cmd> 2>&1
Redirect stdout and stderr to file: <cmd> &> <file>
Pipelines, lists of commands, and grouping commands
Pipe stdout to stdin: <cmdA> | <cmdB>
Pipe stdout and stderr to stdin: <cmdA> |& <cmdB>
Execute in background (subshell): <cmd> &
Execute in sequence: <cmdA> ; <cmdB>
Execute in sequence if previous success: <cmdA> && <cmdB>
Execute in sequence if previous failure: <cmdA> || <cmdB>
Grouping: { <cmdA> ; <cmdB> ; <cmdC> ; }
Grouping (in subshell): ( <cmdA> ; <cmdB> ; <cmdC> )
Grouping can be used to apply redirection or background execution to a sequence of commands.
3.2.3 Pipelines
3.2.4 Lists of Commands
3.2.5.3 Grouping Commands
Variables and variable expressions
Set variable:
VAR=<value>
Use variable (“expansion”): ${VAR}
Value of variable whose name is the value of the variable: ${!VAR}
Length of variable: ${#VAR}
Part from offset: ${parameter:<offset>}
Part from offset up to length: ${parameter:<offset>:<length>}
Part from offset up to negative offset: ${parameter:<offset>:-<offset>}
These apply to characters in strings or elements of an array.
Without shortest matching pattern at the beginning: ${VAR#<pattern>}
Without longest matching pattern at the beginning: ${VAR##<pattern>}
Without shortest matching pattern at the end: ${VAR%<pattern>}
E.g. filename without extension: ${FILENAME%.*}
Without longest matching pattern at the end: ${VAR%%<pattern>}
Replace first occurrence of pattern by string: ${VAR/<pattern>/<string>}
Replace all occurrences of pattern by string: ${VAR//<pattern>/<string>}
Translate to uppercase: ${VAR@U}
Translate to lowercase: ${VAR@L}
Separate file path into its parts
dirname="${pathname%/*}"
name="${pathname##*/}"
basename="${name%.*}"
extension="${name##*.}"
if [ "$dirname" == "$pathname" ]; then
dirname="."
fi
if [ "$extension" == "$basename" ]; then
extension=""
fi
Special variables
Number of positional parameters: $#
Positional parameters: $1
, $2
, $3
, …
Positional parameter from index in variable: ${!<var>}
Last exit status: $?
PID of last background process: $!
"$*"
is equivalent to "$1 $2 …"
"$@"
is equivalent to "$1" "$2" …
.
Outside of quotes, both $*
and $@
are equivalent to $1 $2 …
.
Almost always, "$@"
is the right choice.
Pause and user input
# wait for keypress
read -n 1
# show text and wait for keypress
read -n 1 -p "text"
# show text, wait for keypress, and store it in variable
read -n 1 -p "text" var
# show text, read string, and store it in variable
read -p "text" var
Arrays
The command
args=(
--cap-add=NET_ADMIN
--log-driver json-file
--log-opt max-size=10m)
creates an array with five elements (elements are separated by whitespace).
Access element by index: ${args[<index>]}
${args}
evaluates to the first element, ${args[0]}
"${args[*]}"
is equivalent to "${args[0]} ${args[1]} …"
"${args[@]}"
is equivalent to "${args[0]}" "${args[1]}" …
.
Outside of quotes, both $*
and $@
are equivalent to ${args[0]} ${args[1]} …
.
Shell arithmetic
Expressions in $(( ))
are treated as arithmetic. Variables can be referenced without prefixed $
. Multiple expressions can be separated with ,
, and the last value is returned.
Numerical operators: +
, -
, *
, /
, %
, **
.
Increment and decrement, pre- and post-: ++
, --
.
Assignment: =
, +=
, -=
, *=
, /=
, %=
.
Conditional if
E.g. check whether NUM
is numerically zero, and if yes print a message:
if [[ $NUM -eq 0 ]] ; then echo "Equals zero" ; fi
String comparison operators: >
, <
, =
or ==
, !=
.
Integer comparison operators: -gt
, -lt
, -ge
, -le
, -eq
, -ne
.
Logical operators: &&
, ||
, !
.
Regular file exists: -f <name>
.
Directory exists: -d <name>
.
Length of string is zero: -z <string>
.
Length of string is nonzero: -n <string>
.
Grouping by: (
, )
.
=
or ==
can also take a pattern as its second argument, =~
matches with a regular expression.
[[
is a bash-builtin command which indicates the result through its exit code. It can also be used with while
and until
loops.
3.2.5.2 Conditional Constructs
6.4 Bash Conditional Expressions
3.2.5.1 Looping Constructs
Multiple conditional case
echo -n "Enter the name of an animal: "
read ANIMAL
echo -n "The $ANIMAL has "
case $ANIMAL in
horse | dog | cat)
echo -n "four"
;;
man | kangaroo )
echo -n "two"
;;
*)
echo -n "an unknown number of"
;;
esac
echo " legs."
Each clause is defined by a pattern to be matched with the specified value, and patterns are checked in sequence.
for
loop
Over integers, from START
to END
:
for (( NUM = START; NUM <= END; NUM++ )); do echo $NUM ; done
In this form, the for (( ))
, the parentheses contain three arithmetic expressions.
Over a list, e.g. of directory entries:
for NAME in * ; do echo $NAME ; done
while
loop and read file line by line
while IFS= read -r line; do
echo "Text read from file: $line"
done < $FILENAME
The same construct can also be piped into.